home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Storage / Bento / CM / CMSesOps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  15.8 KB  |  365 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:          CMSesOps.c  
  3.  
  4.     Contains:    Container Manager Session Operations
  5.  
  6.     Written by:    Ira L. Ruben
  7.  
  8.     Owned by:    Ed Lai
  9.  
  10.     Copyright:    © 1992 - 1996 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.  
  14.          <4>     8/13/96    DM        1362809: disable containers on error
  15.          <3>     3/15/96    DM        1291411: compiler independent version
  16.                                     declaration
  17.          <2>     1/15/96    TJ        Cleaned Up
  18.          <3>     9/29/94    RA        1189812: Mods for 68K build.
  19.          <2>     8/26/94    EL        #1181622 Ownership update.
  20.          <1>      2/3/94    EL        first checked in
  21.          <3>    11/22/93    EL        Add refcon for alloc and free handers.
  22.          <2>     10/4/93    EL        nextContainer is not used in CMEndSession
  23.  
  24.     To Do:
  25. */
  26.  
  27. /*---------------------------------------------------------------------------*
  28.  |                                                                           |
  29.  |                           <<<   CMSesOps.c   >>>                          |
  30.  |                                                                           |
  31.  |                    Container Manager Session Operations                   |
  32.  |                                                                           |
  33.  |                               Ira L. Ruben                                |
  34.  |                                  7/27/92                                  |
  35.  |                                                                           |
  36.  |                    Copyright Apple Computer, Inc. 1992-1994               |
  37.  |                           All rights reserved.                            |
  38.  |                                                                           |
  39.  *---------------------------------------------------------------------------*
  40.  
  41.  The API routines in theis file handle Container Manager session operations.  All Container
  42.  Manager calls take place in the context of a "session".  A session must be established
  43.  before any other Container Manager calls are performed and the session closed when all
  44.  calls are completed.
  45.  
  46.  Sessions are referenced in terms of session refNum's and passed to various other API
  47.  routines.  Basically a session represents "global information" (data) the Container
  48.  Manager needs to communicate among its internal routines.  This is information global
  49.  to all containers of a session.
  50.  
  51.  There is nothing prohibiting multiple sessions, although there is no reason for it either.
  52.  A session "refCon" is provided to allow the user to add additional information.
  53. */
  54.  
  55.  
  56. #include <stddef.h>
  57. #include <stdio.h>
  58.  
  59. #ifndef __CMVERSION__
  60. #include "CMVers.h"   
  61. #endif
  62. #ifndef __CMTYPES__
  63. #include "CMTypes.h"
  64. #endif
  65. #ifndef __CM_API__
  66. #include "CMAPI.h"
  67. #endif
  68. #ifndef __LISTMGR__
  69. #include "ListMgr.h"
  70. #endif
  71. #ifndef __SESSIONDATA__
  72. #include "Session.h"          
  73. #endif
  74. #ifndef __HANDLERS__
  75. #include "Handlers.h"
  76. #endif
  77. #ifndef __CONTAINEROPS__
  78. #include "Containr.h"  
  79. #endif
  80. #ifndef __BUFFEREDIO__
  81. #include "BufferIO.h"  
  82. #endif
  83. #ifndef __GLOBALNAMES__
  84. #include "GlbNames.h"   
  85. #endif
  86. #ifndef __ERRORRPT__
  87. #include "ErrorRpt.h"      
  88. #endif
  89.  
  90.                                                                     CM_CFUNCTIONS
  91.  
  92. /* The following generates a segment directive for Mac only due to 32K Jump Table             */
  93. /* Limitations.  If you don't know what I'm talking about don't worry about it.  The        */
  94. /* default is not to generate the pragma.  Theoritically unknown pragmas in ANSI won't    */
  95. /* choke compilers that don't recognize them.                                                                                      */
  96.  
  97. #if CM_MPW
  98. #pragma segment SessionOps
  99. #endif
  100.                                                                                                                                         
  101.  
  102. /*----------------------------------------------------------*
  103.  | Copyright Apple Computer, Inc. 1991-1992 by Ira L. Ruben |
  104.  *----------------------------------------------------------*
  105.  
  106.  This bit of nonsense is to "bury" the copyright notice into a number of places in the
  107.  code.  We define the notice as a string macro so that we can call this routine.  
  108.  The call is done to make sure it is not dead-code-stripped on systems like the Mac MPW
  109.  linker that are smart enough to do such things.
  110.  
  111.  Note, when generating the code using Mac MPW, the call will generate the copyright in the
  112.  code since we compile with the -b2 option in the Mac MPW developement system C compiler.
  113.  
  114.  The actual copyright string macro, called Copyright, is defined in the header CMVersion.h.
  115.  Note, that we repeat the copyright string here as the name of this function just to be
  116.  "wise guys" (it comes from the Copyright_Apple_Computer macro).
  117. */
  118.  
  119. static char CM_PTR * CM_NEAR Copyright_Apple_Computer(char *c)
  120. {
  121.     return (c = Copyright);
  122. }
  123.  
  124.  
  125. /*-----------------------------------------------------------------*
  126.  | CMStartSession - initialize the Container Manager for a session |
  127.  *-----------------------------------------------------------------*
  128.  
  129.  This call is used for all global initialization of a Container Manager session.  It MUST
  130.  be called BEFORE ANY OTHER Container Manager routine.  If not, then every API routine will
  131.  (try to) exit without doing anything (assuming it doesn't blow up before it can detect
  132.  that CMStartSession() wasn't called).
  133.  
  134.  An anonomous non-NULL pointer is returned if initialization is successful.  NULL is 
  135.  returned for failure unless the error reporter (discussed below) aborts execution.  
  136.  
  137.  The returned pointer MUST be passed to every CMOpen[New]Container() that follows.  It
  138.  represents a pointer to private Container Manager data that is global to all open
  139.  containers.  The intent is that this data is unique to the currently running session (or
  140.  task).  The caller may extend this data to include his or her own special per-session
  141.  information.  This is done with the "reference constant" (refCon) passed as the last
  142.  parameter to this routine.  It is saved in the session data.  The refCon can be anything.
  143.  But usually it will be a pointer to the caller's own session data.  
  144.  
  145.  Since the session global data is global to all containers, all containers must have
  146.  accesses to it.  That is why it is passed to CMOpen[New]Container().  Thus all accesses
  147.  to the session data are through container refNums (CMContainer).
  148.  
  149.  Routines are provided to allow the user to set or get the session refCon as a function
  150.  of a container refNum (see CMGetSessionRefCon() and CMSetSessionRefCon()).
  151.  
  152.  CMStartSession() takes as its main parameter the address of a special metahandler. It is 
  153.  similar in function to CMSetMetaHandler() except that here the metahandler is container
  154.  independent and is used to get the address of the error reporting, memory allocator and
  155.  memory deallocator handler routines.  ALL of these handlers MUST be defined.
  156.  
  157.  The metahandler is called with pre-defined operation types for the handlers.  The associated
  158.  handler address is returned.  If any are NULL, NULL will be returned.  If we at least get
  159.  the error handler address, then an error will be reported prior to return.
  160.  
  161.  All three handler routines are available to the user, usually a handler writer through
  162.  the CMMalloc(), CMFree(), and CMError() API calls.
  163.  
  164.  Note that the session data is allocated with the memory allocator returned from the
  165.  metahandler.  Also the session pointer doubles as a switch which is used by all the API
  166.  CM... routines to see if CMStartSession() was indeed called.  If it is NULL, all the
  167.  routines just exit without doing anything.  But there is NO guarantee that the pointer
  168.  was initialized as NULL!  Hence most likely the user will blow up before we ever get a
  169.  chance to get at the session pointer from a container refNum.  It's the best we can do.
  170.  Moral -- Follow the rules and call CMStartSession().
  171. */
  172.  
  173. CMSession CM_FIXEDARGS CMStartSession(CMMetaHandler metaHandler, CMRefCon sessionRefCon)
  174. {
  175.     SessionGlobalDataPtr sessionData;
  176.         
  177.     const char* version = (const char*) CMVersion;
  178.         
  179.     MallocProto                  cmMalloc;
  180.     FreeProto                      cmFree;
  181.     ErrorProto                   cmReportError;
  182.     
  183.     /* Make the Apple lawyers happy.  The following has the effect of burying a copyright    */
  184.     /* notice into the code and, because we're doing a call, stopping any possible dead        */
  185.     /* code stripping.                                                                                                                                      */
  186.     
  187.     Copyright_Apple_Computer(Copyright);
  188.     
  189.     /* Use the provided metahandler to get the routine addresses of the error reporting,    */
  190.     /* malloc, and free handlers.  First the error handler...                                                            */
  191.     
  192.     if (metaHandler == NULL) return (NULL);        /* safety                                                                        */
  193.     
  194.     cmReportError = *(ErrorProto)(*metaHandler)(NULL, (CMGlobalName)CMErrorOpType);
  195.     if (cmReportError == NULL) return (NULL);    /* if no error handler, screw it!                        */
  196.     
  197.     /* Now we can go after the other handlers and report errors if we don't get 'em...         */
  198.     
  199.     cmMalloc = *(MallocProto)(*metaHandler)(NULL, (CMGlobalName)CMAllocOpType);
  200.     cmFree      = *(FreeProto)(*metaHandler)(NULL, (CMGlobalName)CMFreeOpType);
  201.     
  202.     if (cmMalloc == NULL || cmFree == NULL) {
  203.         (*cmReportError)(CM_err_MissingHandler);
  204.         return (NULL);
  205.     }
  206.     
  207.     /* Allocate the space for the session (task) global data area...                                            */
  208.     
  209.     sessionData = (SessionGlobalDataPtr)(*cmMalloc)((CMSize)(sizeof(SessionGlobalData) + strlen(version)), sessionRefCon);
  210.     if (sessionData == NULL) {
  211.         (*cmReportError)(CM_err_NoSession);
  212.         return (NULL);
  213.     }
  214.         
  215.     /* Initialize the session global data...
  216.                                                                                                                      Prime user (client)                    */
  217.     sessionData->cmMalloc                     = cmMalloc;                            /* Handlers.h                                        */
  218.     sessionData->cmFree                         = cmFree;                                /* Handlers.h                                        */
  219.     sessionData->cmReportError          = cmReportError;                /*    ErrorRpt.h                               */
  220.     sessionData->cmTocTblSize             = DefaultIndexTableSize;/*    CMCntOps.c                               */
  221.     sessionData->cmDbgFile                = NULL;                                    /* anywhere                                            */
  222.     sessionData->metaHandlerTable = NULL;                                    /* Handlers.c                                        */
  223.     sessionData->refCon                      = sessionRefCon;                /*   CMHndOps.c                                  */
  224.     sessionData->success                    = true;                                    /* anywhere                                            */
  225.     sessionData->aborting                    = false;                                /*    CMCntOps.c                               */
  226.     cmInitList(&sessionData->openContainers);                            /*    CMCntOps.c                               */
  227.     strcpy(sessionData->cmVersion, version);                            /* actually no one!                            */
  228.     
  229.     #if CMVALIDATE
  230.     sessionData->validate                    = CMDEFAULT_VALIDATE;        /*    ErrorRpt.h                               */
  231.     #endif
  232.     
  233.     return ((CMSession)sessionData);                    /* success                                                                    */
  234. }
  235.  
  236.  
  237. /*------------------------------------------------------*
  238.  | CMEndSession - terminate a Container Manager session |
  239.  *------------------------------------------------------*
  240.  
  241.  This should be called as the LAST call to the Container Manager.  If frees the space
  242.  allocated for the session by CMStartSession() and optionally calls CMCloseContainer() on
  243.  all remaining open containers.
  244.  
  245.  The sessionData specifies the session data pointer returned from CMStartSession().  If
  246.  closeOpenContainers is passed as 0 (i.e., "false"), then an error is reported for each
  247.  container that has NOT been explicitly closed by CMCloseContainer(). If true (non-zero) is
  248.  specified, then the Container Manager will call CMCloseContainer() for you for each
  249.  remaining open container.
  250.  
  251.  The difference between specifying closeOpenContainers as false, as opposed to true, is
  252.  that open containers are NOT formally closed.  They remain in whatever (open) state they
  253.  currently happen to be in when the error is reported.  This is generally true whenever
  254.  any error is reported.  When true is passed, open containers are not treated as an error
  255.  condition, and closed by calling the API CMCloseContainer() routine just as any API caller
  256.  would.  This case can be viewed as a "close all" case.
  257.  
  258.  No further calls should be done once this routine is called.  All memory occupied by the
  259.  containers, as well as the session itself are freed.
  260. */
  261.  
  262. void CM_FIXEDARGS CMEndSession(CMSession sessionData, CMBoolean closeOpenContainers)
  263. {
  264.     SessionGlobalDataPtr session = (SessionGlobalDataPtr)sessionData;
  265.     ContainerPtr container;
  266.  
  267.     if (sessionData == NULL) return;                            /* exit if there is no session to close    */
  268.     
  269.     /* Go through the list of open containers and do what it says above...                                */
  270.     
  271.     container = (ContainerPtr)cmGetListHead(&session->openContainers);
  272.     
  273.     while (container != NULL) {                                        /* look at each open container...                */
  274.         if (closeOpenContainers)                                        /* if user wants US to close it...            */
  275.             CMCloseContainer((CMContainer)container);    /* ...we'll do it for the "lazy" user        */
  276.         else {                                                                            /* if open containers aren't expected...*/
  277.             Container_Disable(container);
  278.             ERROR1(CM_err_StillOpen, CONTAINERNAME);    /* ...YELL loudly!                                            */
  279.             cmFreeAllGlobalNames(&container->globalNameTable); /* if error reporter returns...*/
  280.             cmFreeAllIOBuffers(container);                                         /* ...free any I/O buffers            */
  281.             cmFreeTOC(container, &container->toc);                         /* ...free container memory        */
  282.             CMfree(cmDeleteListCell(&session->openContainers, container));
  283.         }
  284.         
  285.         /* We always use the container list head because the open container queue could            */
  286.         /* contain embedded containers.  These "go away" implicitly by closing the embedde's*/
  287.         /* parents.  That will remove them from the open queue.  By using the queue head we    */
  288.         /* always get the "next" available truly open container.                                                        */
  289.         
  290.         container = cmGetListHead(&session->openContainers);
  291.     }
  292.     
  293.     /* Now that the containers are disposed of, we can free the session data.  This    */
  294.     /* is the methandler table and the session data itself.  After that the user is on         */
  295.     /* his (or her) own!                                                                                                                                    */
  296.     
  297.     cmFreeAllMetaHandlers(session);                                /* there go the metahandler names                */
  298.     
  299.     SessionFree(session);                                                    /* and there goes the session itself        */
  300. }
  301.  
  302.  
  303. /*----------------------------------*
  304.  | CMAbortSession - abort a session |
  305.  *----------------------------------*
  306.  
  307.  ALL containers are closed WITHOUT further writing to those containers, i.e., as if all
  308.  containers were opened for reading even when opened for writing.  The session is then 
  309.  closed with CMEndSession().  This is intended to be used to abort the session from
  310.  unrecoverable errors.
  311.  
  312.  All memory allocated by ALL the container data structures are freed (if possible) and the
  313.  container close handlers called to physically close the containers.  All dynamic values
  314.  currently in use are released in an attempt to allow them to properly clean up any files
  315.  and memory allocated by their handlers.  No further API calls should be done.
  316.  
  317.  Note: CMAbortSession() is basically a CMAbortContainer() for EACH currently open container
  318.  followed by a CMEndSession().  Also, this routine WILL return to its caller.  It is up to
  319.  the user to actually abort execution if that is required.
  320. */
  321.  
  322. void CM_FIXEDARGS CMAbortSession(CMSession sessionData)
  323. {
  324.     if (sessionData == NULL) return;                                            /* exit if there is no session    */
  325.  
  326.     if (((SessionGlobalDataPtr)sessionData)->aborting)        /* ignore recursive aborts!            */
  327.         return;                                            
  328.     
  329.     ((SessionGlobalDataPtr)sessionData)->aborting = true;    /* throw the deadly switch            */
  330.     
  331.     CMEndSession(sessionData, true);                                            /* abort all containers                 */
  332. }
  333.  
  334.  
  335. /*--------------------------------------------------------*
  336.  | CMGetSessionRefCon - return the current session refCon |
  337.  *--------------------------------------------------------*
  338.  
  339.  This routine can be used to get at the user's session refCon saved as part of the session
  340.  data created by CMStartSession().  The session data is "tied" to each container created by
  341.  CMOpen[New]Container().  Thus the refCon is accessed via a container refNum.
  342. */
  343.  
  344. CMRefCon CM_FIXEDARGS CMGetSessionRefCon(CMContainer container)
  345. {
  346.     return ((container == NULL || SESSION == NULL) ? NULL : SESSION->refCon);
  347. }
  348.  
  349.  
  350. /*-----------------------------------------------------*
  351.  | CMSetSessionRefCon - change the session data refCon |
  352.  *-----------------------------------------------------*
  353.  
  354.  This routine may be called to change the user's session refCon associated with the session
  355.  data.  As with CMGetSessionRefCon() above, the session data is accessed through a
  356.  container refNum.
  357. */
  358.  
  359. void CM_FIXEDARGS CMSetSessionRefCon(CMContainer container, CMRefCon refCon)
  360. {
  361.     SESSION->refCon = (container == NULL || SESSION == NULL) ? NULL : refCon;
  362. }
  363.                                                           
  364.                                                             CM_END_CFUNCTIONS
  365.